#include <mmu/mmu.h>
#include <mmu/physical.h>
#include <mmu/paging.h>



/*
 * Ci dice se la pagina dopo x e y degli argomenti e' libera
 * e aggiorna x e y in caso positivo
 */
int phy_if_free_page(int *x, int *y)
{
	if(*y == 31)
	{
		*y = 0;
		*x = *x + 1;
	}
	else
		*y = *y + 1;
	
	if((phy_bitmap[(int) *x] & (1 << (int) *y)) == 1)	
		return 0;
	else
		return 1;
}

/*
 * Richiedi pagine
 */
void *phy_get_pages(unsigned size)
{
	unsigned adr;
	unsigned x;
	unsigned y;
	unsigned j,i;
	unsigned a,b;
	int ff;
	
	
	x = 0;
	while(x < phy_page_number/32)
	{
		y = 0;
		while(y < 32)
		{		
			if((phy_bitmap[x] & (1 << y)) == 0)
			{	
				a = x;
				b = y;
				for(j = 0; j <= size; j++)
				{
					if(j == size)
					{
						// Riempie la bitmap
						phy_bitmap[x] = phy_bitmap[x] + (1 << y);

						for(j = 1; j < size; j++)
						{
							if(y == 31)
							{
								y = 0;
								x++;
							}
							else
								y = y + 1;

							phy_bitmap[x] = phy_bitmap[x] + (1 << y);
						}

				
						adr = (x * 1024 * 32 * PHY_PAGE_SIZE) + (y * 1024 * PHY_PAGE_SIZE);

						ff = phy_first_free_alloc();
						phy_allocated[ff].address = (void *) adr;
						phy_allocated[ff].dim = size;
						//printf("\nGet page %d at %d of size %d on position %d\n", (x * 32 + y), adr, size, ff);
						return (void *) adr;
					}
					if(!phy_if_free_page(&a, &b))
					{
						x = a;
						y = b;
						break;
					}
				}
			}
			y++;
		}
		x++;
	}

	// Non ci sono pagine disponibili
	return (void *) -1;
}


/*
 * Inizializza il gestore fisico
 */
void phy_init()
{
	unsigned x;
	
	// Mettiamo tutto a zero	
	for(x = 0; x < phy_page_number/32; x++)
			phy_bitmap[x] = 0;
			
	// Pero' il kernel utilizza memoria u.u
	//for(x = 0; x < (MMU_KERNEL_RESERVED_PAGES)/32; x++)
	//	phy_bitmap[x] = 0xFFFFFFFF;


	// Azzera la tabella delel allocazioni
	for(x = 0; x < PHY_MAX_BLOCKS; x++)
		phy_allocated[x].dim = 0;
}

/*
 * Rilascia pagine
 */
void phy_relase_pages(void *address)
{
	unsigned x;
	unsigned y;
	unsigned i;
	unsigned j;
	
	// Dealloca dalla lista delle allocazioni e azzera la bitmap
	for(i = 0; i < PHY_MAX_BLOCKS; i++)
		if(phy_allocated[i].address == address)
		{
			// Azzera i bit della bitmap
			x = ((unsigned) address/4096)/32;
			y = ((unsigned) address/4096)%32;

			phy_bitmap[x] = phy_bitmap[x] - (1 << y);
	
			for(j = 1; j < phy_allocated[i].dim; j++)
			{
				if(y == 31)
				{
					y = 0;
					x++;
				}
				else
					y = y + 1;

				phy_bitmap[x] = phy_bitmap[x] - (1 << y);
			}
			//printf("Relasing %d of %d on position %d\n",address,phy_allocated[i].dim,i); 


			// Libera l'elemento della lista
			phy_allocated[i].dim = 0;
		
			break;
		}
}


/*
 * Trova il primo spazio libero nella tabella delle allocazioni
 */
int phy_first_free_alloc()
{
	int x;
	for(x = 0; x < PHY_MAX_BLOCKS; x++)
		if(phy_allocated[x].dim == 0) return x;

	return -1;
}

/*
 * Restituisce il numero totale della pagine 
 */
unsigned phy_tot_pages()
{
	// Per  avere le pagine esatte, grazie all'arrotondamento
	// della divisione. Perdiamo massimo 32 pagine, ma sticazzi u.u
	return ((((unsigned) mmu_memory / PHY_PAGE_SIZE)/32)*32);
}





/*
 * Restituisce il numero di pagine libere
 */
unsigned phy_get_nfree_pages()
{
	unsigned np = 0;
	unsigned x;
	unsigned y;
	
	for(x = 0; x < phy_page_number/32; x++)
	{
		for(y = 0; y < 32; y++)
			if((phy_bitmap[x] & (1 << y)) == 0)
				np++;
	}
	return np;	
}

